/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
/*
 * Toplogy Viewer
 */


package cgl.narada.topology.viewer;

import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * This class represents all the super super clusters consisting of super 
 * clusters. The super super cluster is fourth level in the node address. If
 * node's address is 1.2.3.4 then the super super cluster id is 1
 */
public class SSCluster extends Node {
    public List superClusters;
    
    /**
     * Empty Constructor
     */
    public SSCluster() {
    }

    /**
     * Constructor initializing the id of this super super cluster.
     */
    public SSCluster(int pSSClusterId) {
	// form a node for this cluster. Initialize all the Ids and Position.
	super(pSSClusterId, INVALID_VALUE, INVALID_VALUE, INVALID_VALUE);
	superClusters = new ArrayList();
    }

    /**
     * Adds a new super cluster to the list. Depending upon the total number of
     * super clusters in the list, decide the new positions for each of the
     * super cluster. 
     * @param  superClusterId id of a super cluster.
     * @param  clusterId id of a cluster.
     * @param  nodeId id of a node.
     * @throws TopologyException if due to some problem. super cluster is
     *         found null during insertion of a node
     */
    public void insertSuperCluster(int superClusterId, int clusterId, 
				   int nodeId) 
	throws TopologyException {
	// Addition of the super cluster
	SCluster superCluster = getSuperCluster(superClusterId);
	if (superCluster == null) {
	    superCluster = new SCluster(superClusterId, this.nodeId);
	    superClusters.add(superCluster);	
	    repositionSuperClusters();
	}
	// Addition of the cluster
	superCluster = getSuperCluster(superClusterId);
	if (superCluster == null) {
	    throw new TopologyException("super cluster not found while"
					+ "insertion");
	} else {
	    superCluster.insertCluster(clusterId, nodeId);
	}
    }
    
    /**
     * Deletes an existing super cluster inside the super super cluster.
     * Repositions all other nodes reculrsively.
     * @param  superClusterId id of a super cluster.
     * @param  clusterId id of a cluster.
     * @param  nodeId id of a node.
     * @param  nodesToBeDeleted a <code>List</code> which will contain node
     *         addresses of the nodes being deleted.
     * @throws TopologyException if no such super cluster id found while node 
     *         deletion.
     */
    public void deleteSuperCluster(int superClusterId, int clusterId, 
				   int nodeId, List nodesToBeDeleted) 
	throws TopologyException {
	List deletedNodes = null;
	Iterator it = superClusters.iterator();
	boolean superClusterFound = false;
	while ((it.hasNext()) && (!superClusterFound)) {
	    SCluster superCluster = (SCluster) it.next();
	    if (superCluster.nodeId == superClusterId) {
		if (clusterId == INVALID_VALUE) {
		    superCluster.deleteAllClusters(nodesToBeDeleted);
		} else {
		    superCluster.deleteCluster(clusterId, nodeId, 
					       nodesToBeDeleted);
		}
		// if the super cluster is empty then delete it
		if (superCluster.clusters.isEmpty()) {
		    it.remove();
		    repositionSuperClusters();
		}
		superClusterFound = true;
	    }
	}
	if (!superClusterFound) {
	    throw new TopologyException("error in node deletion");
	}
    }

    /**
     * Deletes all the super clusters present in this super super cluster.
     * @param nodesToBeDeleted a <code>List</code> which will contain node
     *        addresses of the nodes being deleted.
     */
    public void deleteAllSuperClusters(List nodesToBeDeleted) {
	Iterator it = superClusters.iterator();
	while (it.hasNext()) {
	    SCluster sc = (SCluster) it.next();
	    sc.deleteAllClusters(nodesToBeDeleted);
	    it.remove();
	}
    }

    /**
     * Finds out super cluster nearest to the specified coordinates. Then
     * passes control to the super cluster for finding a nearest cluster.
     * @param  x X-coordinate
     * @param  y Y-coordinate
     * @return <code>Node</code> nearest to specified coordinates.
     */
    public Node getNodeAtParticularCoordinates(int x, int y) {
	SCluster sc = 
	    (SCluster) PositionCalculation.getNearestNode(superClusters, x, y);
	if (sc != null) {
	    return sc.getNodeAtParticularCoordinates(x, y);
	}
	return null;
    }

    /**
     * Draws the super super cluster only if its part is visible on the screen.
     * Draws all the super clusters inside it.
     * @param  g <code>Graphics</code> object for image drawing.
     * @param  limitX1 lower limit for X-coordinate
     * @param  limitY1 lower limit for Y-coordinate
     * @param  limitX2 upper limit for X-coordinate
     * @param  limitY2 upper limit for Y-coordinate
     */
    public void drawSuperSuperCluster(Graphics g, int limitX1, int limitY1,
				      int limitX2, int limitY2) {
	if (this.canFitOnPanel(limitX1, limitY1, limitX2, limitY2)) {
	    this.drawNode(g, limitX1, limitY1, limitX2, limitY2);
	    Iterator itSClusters = superClusters.iterator();
	    while (itSClusters.hasNext()) {
		SCluster sc = (SCluster) itSClusters.next();
		sc.drawSuperCluster(g, limitX1, limitY1, limitX2, limitY2);
	    }
	}
    }
    
    /**
     * Returns a node in this super super cluster with specified super 
     * cluster, cluster and node id.
     * @param  superClusterId id of a super cluster.
     * @param  clusterId id of a cluster.
     * @param  nodeId id of a node.
     * @return <code>Node</code> 
     */
    public Node getParticularNode(int superClusterId, int clusterId,
				  int nodeId) {
	SCluster superCluster = getSuperCluster(superClusterId);
	if (superCluster != null) {
	    return superCluster.getParticularNode(clusterId, nodeId);
	}
	return null;
    }

    /**
     * Gets the new <code>Position</code> objects and assign then to all the 
     * super clusters inside this super super cluster. Recurdively calls
     * repositionNodes() for each of the super cluster.
     */
    public void repositionSuperClusters() {
	List newPositions = getNewPositions();
	Iterator itPosition = newPositions.iterator();
	Iterator itSuperCluster = superClusters.iterator();
	while (itSuperCluster.hasNext()) {
	    SCluster sc = (SCluster) itSuperCluster.next();
	    Position p = (Position) itPosition.next();
	    sc.nodeLocation = p;
	    sc.repositionClusters();
	}
    }

    /**
     * Returns particular super cluster with specified id
     * @param  superClusterId id of a super cluster.
     * @return <code>SCluster</code>
     */
    private SCluster getSuperCluster(int superClusterId) {
	Iterator it = superClusters.iterator();
	while (it.hasNext()) {
	    SCluster sc = (SCluster) it.next();
	    if (sc.nodeId == superClusterId) {
		return sc;
	    }
	}
	return null;
    }

    /**
     * Returns a <code>List</code> containing <code>Position</code> objects
     * for all the super clusters inside this super super cluster.
     * @return <code>List</code> of new Position objects.
     */
    private List getNewPositions() {
	int numberOfNodes = superClusters.size();
	return PositionCalculation.getNewPositions(this.nodeLocation,
						   numberOfNodes, 2);	    
    }
};
